/**
 * Query the DOM of all elements matching a CSS selector string.
 *
 * Currently the function supports all CSS3 selectors as advertised in the CSS3 spec. 
 * [http://www.w3.org/TR/css3-selectors/] with the exceptions of (E:link, E:visited, 
 * E:active, E:hover, E:focus, E:target, E:lang). It attempts to use native methods 
 * where available and always returns an array.
 *
 * Author / Copyright (C) 2008 Borgar Thorsteinsson
 * Licenced under the terms and conditions of the MIT licence 
 * [http://borgar.undraland.com/programs/dom-get/licence.txt].
 * 
 */
(function () {

  // TODO: Add detection/triggering of uniquing

  // ====================================

  var _disableNative = 0,   // disables the use of document.querySelectorAll (for testing, debugging)
      _cleanUps      = 0,   // disable cleanups, gives extra speed, but DOM is not left exactly as found (yes, it's ok)

  // ====================================

      domget, 
      doc    = document,
      R      = RegExp,

      // we'll need to know if this is mr. MSIE so we can optimize for him
      msie = 0 /*@cc_on + 1 @*/,
      ua_version = parseFloat((navigator.userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/i) || [])[1]),
      
      _nativeClass = !_disableNative && doc.getElementsByClassName && /\[native code\]/.test( doc.getElementsByClassName.toString() );

  // ====================================
  // some helper methods and objects
  // these would/could be replaced with library calls if we had them...
  
  function trim ( str ) {
  	str = str.replace(/^\s\s*/, '');
  	var w = /\s/, i = str.length;
  	while (w.test( str.charAt( --i ) ));
  	return str.slice(0, i + 1);
  };

  var toArray = (!msie)
    ? function ( o, i, l ) { return [].slice.call( o, i||0, l||o.length ); }
    : function ( n ) { for (var a=[], i=0, l=n.length; i<l; i++) { a[i] = n[i]; } return a; };

	// find an index of elm with a collection (array or nodelist) of elms
	var _dArray = [];
	var indexOf = (_dArray.indexOf && /\[native code\]/.test( _dArray.indexOf.toString() ))
	  // use native
	  ? function ( elms, elm ) {
	      return (elms.indexOf) 
	        ? elms.indexOf( elm )
	        : _dArray.indexOf.call( elms, elm );  // only a teensy beet faster than brute-force
	    }
	  // fallback
	  : function ( elms, elm ) {
    	  var n = -1;
    	  while (elms[++n]) { if (elms[n] === elm) { return n; } };
    	  return -1;
	    };
  // ====================================

  var _tokenCache    = {},
      _selectorCache = {},
      _nthCache      = [],
      _nthCacheIE    = {},
      _nthLenCache   = {},
      _classCache    = {},
	    _dupeKey       = (new Date()).getTime(),
  
  _nth = {
    'even' : '2n',
    'odd'  : '2n+1'
  },
  
  _regExp = {
    operator    : /^(\s*([>+~])?\s*)/,
    split       : /\s*([ >+~]+[^ >+~=\d])/, 
    tagName     : /^([ >+~]*([a-z1-6]+|\*))/i, 
    id          : /^(#([a-z][a-z0-9_-]*))/i,
    className   : /^(\.([a-z0-9_-]+))/i,
    attr        : /^(\[([\w-]+)\s?(?:(.=|=)\s?['"]?(.*?)["']?)?\])/,
    pseudo      : /^(\:([\w-]+)?(\((.*?\)?)\))?)/,     
    nth         : /(-?)(\d+)?(n[\+\-](\d+))?/,
    nthTest     : /nth(-last)?-(child|of-type)/,
    unsupported : /\:(link|visited|active|hover|focus|target|lang)/i,
    css3        : /\:(root|nth|empty|(en|dis)abled|checked|not)|\^=|\$=|\*=|%=|of\-type|last\-|only\-/i,
    useNative   : /\:contains|!=/i,
    tagOnly     : /^([a-z1-6]+|\*)$/i,
    tagWithId   : /^([a-z1-6]+)?#([a-z][a-z0-9_:-]*)$/i
  },

  // ====================================

  _wipeNthCache = (msie) 
    ? function () { _nthCacheIE = {}; }
    : function () {
        var i=0, l=_nthCache.length;
        if (_cleanUps) {
          for (; i<l; delete _nthCache[i++]._children);  // delete is slow
        }
        else {
          for (; i<l; _nthCache[i++]._children = null);
        }
        _nthCache = [];
      },
  
  // ====================================
  
  filter = {
    
    // "E > F" => Match an F element child of an E element
    byChild : function ( tagName, elms )
    {
      var found = [], i = 0, j = 0, ref, elm;
      while (ref = elms[i++])
      {
        elm = ref.firstChild;
        while (elm)
        {
          if (elm.nodeType == 1 && (tagName === '*' || tagName === elm.nodeName)) 
          {
            found[j++] = elm; 
          }
          elm = elm.nextSibling;
        }
      }
      return found;
    },
    
    // "E + F" => Match an F element immediately preceded by an E element
    byNextSibling : function ( tagName, elms )
    {
      var found = [], i = 0, j = 0, subelms, ref, elm;
      while (elm = elms[i++]) 
      {
        while ((elm = elm.nextSibling) && elm.nodeType !== 1);
        if (elm && (tagName === '*' || tagName === elm.nodeName)) 
        {
          found[j++] = elm;
        }
      }
      return found;
    },
    
    // "E ~ F" => Match an F element preceded by an E element
    bySibling : function ( tagName, elms )
    {
      var found = [], i = 0, j, subelms, ref, elm, siblings, 
          elmIdx, parents = [], parent;
      while (elm = elms[i++]) 
      {
        parent = elm.parentNode;
        if (indexOf(parents, parent) === -1) 
        {
          parents.push( parent );
          elmIdx   = indexOf( parent.childNodes, elm );
          siblings = this.children( parent, tagName );
          j = -1;
          while (ref = siblings[++j]) 
          {
            if (elmIdx < indexOf( ref.parentNode.childNodes, ref ))
            {
              found = found.concat( siblings.slice( j, siblings.length ) );
              break;
            }
          }
        }
      }
      return found;
    },
    
    // "E F" => Match an F element decended from an E element
    byAncestor : function ( tagName, elms )
    {
      var found = [], i = -1, j, n = -1, subelms, ref, elm;
      tagName = tagName || '*';
      while (ref = elms[++i]) 
      {
        subelms = ref.getElementsByTagName( tagName );
        for (j=-1; elm = subelms[++j]; found[++n] = elm);
      }
      return found; 
    },
    
    // E#myid
    // http://www.w3.org/TR/css3-selectors/#id-selectors
    byId : function ( id, elms, not )
    {
      var found = [], i = 0, elm;
      while (elm = elms[i++]) 
      {
        if (not && id !== elm.id) 
        {
          found[found.length] = elm;
        }
        else if (id === elm.id) 
        {
          if (!not) { return [elm]; }
        }
      }
      return found;
    },
    
    // TODO: test this in an older Safari
    idShortCut : function ( id, tagName, elms )
    {
      var idelm = doc.getElementById(id);
      // stop looking if this id does not exist
      if (!idelm || (tagName !== '*' && tagName !== idelm.nodeName)) 
      { 
        return [];
      }
      // ..by here we should have a matched id element
      if (elms.length === 1 && elms[0] === doc) 
      {
        return [idelm];
      }
      // Firefox, Opera
      if (doc.body.compareDocumentPosition) 
      { 
        for (var i=0,l=elms.length; i<l; i++) 
        {
          if (elms[i].compareDocumentPosition(idelm) & 16) 
          {
            return [idelm];
          }
        }
        return []; // out of context
      }
      // IE 
      if (doc.body.contains) 
      {
        for (var i=0,l=elms.length; i<l; i++) 
        {
          if (elms[i].contains(idelm)) 
          {
            return [idelm];
          }
        }
        return []; // out of context
      }
      return elms;
    },
    
    // E.warning
    // http://www.w3.org/TR/css3-selectors/#class-html
    byClassName : function ( className, elms, not )
    {
      var found = [], i = -1, cls = (' '+className+' '), e;
      while (e = elms[++i]) 
      {
  			if ( (e.className && (' '+e.className+' ').indexOf( cls ) !== -1) ^ not ) 
  			{
  			  found[found.length] = e;
  			}
  		}
      return found;
    },

    byClassNameNative : function ( classNames, elms )
    {
      var found = [], i = -1, j, n = -1, subelms, ref, elm;
      while (ref = elms[++i]) 
      {
        subelms = ref.getElementsByClassName( classNames );
        for (j=-1; elm = subelms[++j]; found[++n] = elm);
      }
      return found;
    },

    firstoftype : function ( s, elms, not ) 
    {
      return this.nth( '0n+1', elms, not, '*', 0 );
    },
    lastoftype : function ( s, elms, not ) 
    {
      return this.nth( '0n+1', elms, not, '*', 1 );
    },
    onlyoftype : function ( s, elms, not ) 
    {
      elms = this.nth( '0n+1', elms, not, '*', 0 );
      return this.nth( '0n+1', elms, not, '*', 1 );
    },
    
    // E:nth-child(n), E:nth-last-child(n), E:nth-of-type(n), E:nth-last-of-type(n)
    // http://www.w3.org/TR/css3-selectors/#structural-pseudos
    nth : function ( s, elms, not, tagName, last )
    {
      if (_regExp.nth.test( s )) 
      {
        var interval = (R.$1 + (R.$2 || 1 )) * 1,
            offset   =  R.$3.substr( 1 ) * 1,
            found    = [],
            i        = 0,
            elm, ref, nth, n;

        while (elm = elms[i++]) 
        {
          // find index 
          var index = 0, n = -1, siblings, ref;

          siblings = this.children( elm.parentNode, ((tagName == '*') ? elm.nodeName : tagName ) );
          index    = indexOf( siblings, elm ) +1;
          if (last) {
            index = 1 + siblings.length - index;
          }

          n = index - offset;
          nth = (!interval) ? ( n == 0 ) : ( n % interval == 0 && n / interval >= 0 );
					if ( nth ^ not ) { found[found.length] = elm; }
        }
      }
      return found;
    },
    
    // http://www.w3.org/TR/css3-selectors/#UIstates
    enabled  : function ( s, elm, not ) { 
      return filter.disabled( s, elm, 1 ^ not );
    },
    
    unique : function ( elms ) {
      var found = [], n, i = -1, l = 0, 
          p     = 'domget_counted',
          _key  = 'domget-' + (_dupeKey++);
      while ((n = elms[++i])) 
      {
        if (n[p] !== _key) 
        {
          n[p] = _key;
          found[found.length] = n;
        }
      }
      if (_cleanUps) 
      {
        for (i=0; n=found[i++]; delete n[p]);
      }
      return found;
    },    
    
    prev : function ( elm ) 
    {
      while ((elm = elm.previousSibling) && elm.nodeType !== 1); 
      return elm;
    },
    next : function ( elm ) 
    {
      while ((elm = elm.nextSibling) && elm.nodeType !== 1); 
      return elm;
    },
    
    // this is only ever used by non IE browsers
    // on IE we use E.children
    children : function ( elm, tagName ) 
    {
      // make sure tag is not '*' or lowercase
      tagName = (tagName && tagName !== '*') ? tagName.toUpperCase() : '';
      // fill cache if not present
      if (!elm._children) 
      {
        var found = [], i = 0, ref = elm.firstChild;
        while (ref) 
        {
          if (ref.nodeType === 1) { found[i++] = ref; }
          ref = ref.nextSibling;
        }
        _nthCache.push( elm );  // remember to clean it up later
        elm._children = { '*' : found };
      }

      var ec = elm._children;
      if (tagName && !elm._children[tagName]) 
      {
        ec[tagName] = this.byTagName( tagName, ec['*'], 0 );
      }
      // return children
      return (tagName) ? ec[tagName] : ec['*'] ;
    },
    
    fixAttr : {}
    
  },
  
  // This object contains functions specially optimized for MSIE.
  // They do the same thing as the filters above, but differently; playing to IE's strengths.
  filterIE = {
    
    // the trick here is to only add an item once (based on sourceindex as UID)
    // this reduces the load on all following loops, and eliminates need for unique pass
    byAncestor : function ( tagName, elms )
    {
      var counted = {},
          tagName = tagName || '*',
          found   = [], i=0, j=0, n=0, subelms, elm;
          
      while (ref = elms[i++]) 
      {
        subelms = ref.getElementsByTagName( tagName );
        while (elm = subelms[j++]) 
        {
          if (counted[elm.sourceIndex] !== 1) 
          {
            counted[elm.sourceIndex] = 1;
            found[n++] = elm;
          }
        }
        j = 0;
      }
      return found;
    },
    
    bySibling : function ( tagName, elms )
    {
      var found = [], i = 0, j, m = 0, parents = {},
          ref, elm, siblings, parent;
      while (elm = elms[i++]) 
      {
        parent = elm.parentNode;
        if (!parents[parent.sourceIndex]) // examine each parent only once
        {
          parents[parent.sourceIndex] = 1;
          siblings = (tagName && tagName !== '*') 
              ? parent.children.tags( tagName ) 
              : parent.children;

          j = -1;
          // find first sibling (of tagName) that follows our context element
          while ((ref = siblings[++j])) 
          {
            if ((elm.sourceIndex < ref.sourceIndex)) 
            {
              // all remaining siblings are matches
              for (var x=j,z=siblings.length; x<z; x++) 
              {
                found[m++] = siblings[x]; 
              }
              break;
            }
          }
        }
      }
      return found;
    },
    
    nth : function ( s, elms, not, tagName, last )
    {
      if (_regExp.nth.test( s )) 
      {
        var interval = (R.$1 + (R.$2 || '1' )) * 1,
            offset   =  R.$3.substr(1) * 1,
            found    = [], 
            i        = 0,
            elm, ref, nth, n, len, siblings;

        while (elm = elms[i++]) 
        {
          if (tagName) 
          {
            siblings = elm.parentNode.children.tags( elm.tagName );
            for (index=0; siblings[index] !== elm; index++);
            index++;
            if (last) { index = 1 + siblings.length - index; }
          }
          else 
          {
            if (!_nthCacheIE[elm.sourceIndex]) 
            {
              ref = elm.parentNode.firstChild;
              j = 0;
              do { if (ref.nodeType === 1) { _nthCacheIE[ref.sourceIndex] = ++j; } }
              while (ref = ref.nextSibling);
              // E.parentNode.children.length cannot be trusted as it returns 
              // comment nodes too, so this is cached instead
              _nthLenCache[elm.parentNode.sourceIndex] = j;
            }
            index = _nthCacheIE[elm.sourceIndex];

            if (last) 
            {
              len   = _nthLenCache[elm.parentNode.sourceIndex];
              index = 1 + len - index;
            }
          }
          n = index - offset;
          nth = (!interval) 
                  ? ( n == 0 ) 
                  : ( n % interval == 0 && n / interval >= 0 );
					if ( nth ^ not ) { found[found.length] = elm; }

        }
      }
      return found;
    },
    
    // I've eliminated the need for this by keeping elements unique in IE (see byAncestor)
    // the code is left intact here to demonstrate a way to do faster unique with IE
    // TODO: actually "p,span,p" or "p.class1,p.class2" or such will require unique -- trigger only on "," ?
    unique : function ( elms ) 
    { 
      // faster unique for IE using .sourceIndex
      var found   = [], 
          counted = {}, // TODO: measure if there a speed difference in object vs array?
          s, i, l;   
      for (i = 0, l = elms.length; i < l; i++) 
      {
        if (!counted[(s = elms[i].sourceIndex)]) 
        {
          found[found.length] = elms[i];
          counted[s] = 1;  // true
        }
      }
      return found;
    },

    fixAttr : ((ua_version < 8) ? {
  	  'accesskey'   : 'accessKey',
  	  'cellpadding' : 'cellPadding',
  	  'cellspacing' : 'cellSpacing',
  	  'class'       : 'className',
  	  'colspan'     : 'colSpan',
  	  'for'         : 'htmlFor',
  	  'frameborder' : 'frameBorder',
  	  'ismap'       : 'isMap',
  	  'longdesc'    : 'longDesc',
  	  'maxlength'   : 'maxLength',
  	  'readonly'    : 'readOnly',
  	  'rowspan'     : 'rowSpan',
  	  'tabindex'    : 'tabIndex',
  	  'usemap'      : 'useMap'
  	} : {})

  },

  
  _tokenize = function ( selector ) 
  {
    var _tokens = [], 
        _operator, _last, _pre, _token, _split, s, pn, _wt, _t;
    
    while (selector)
    {
      _operator = _regExp.operator.test( selector ) ? R.$2 : '';
      _pre      = R.$1.length;
      _split    = selector.substring( _pre ).search( _regExp.split );
      _token    = (_split > -1) ? selector.substring( 0, _split + _pre ) : selector;
      selector = trim( selector.substring( _token.length ) );

      // at this point we have a operator + tokenstring to work with
      
      _wt = _token;
      if (!_tokenCache[_wt]) 
      {
        _t = {
          operator   : _operator,
          id         : null,
          className  : [],
          attr       : [],
          pseudo     : []
        };
        _t.tagName = _regExp.tagName.test( _token ) ? R.$2.toUpperCase() : '*',
        _token     = _token.substr( R.$1.length );
      
        _last      = ''; // safety-valve for broken selectors
      
        while (_last !== _token) 
        {
          _last = _token;
          // id
          if (_regExp.id.test( _token )) 
          {
            _t.id  = R.$2;
            _token = _token.substr( R.$1.length );
          }
          // className
          if (_regExp.className.test( _token )) 
          {
            _t.className.push( R.$2 );
            _token = _token.substr( R.$1.length );
          }
          // attribute
          if (_regExp.attr.test( _token )) 
          {
            _t.attr.push({
              name     : filter.fixAttr[R.$2] || R.$2,
              operator : R.$3 || '',
              value    : R.$4 || '',
              selector : R.$1
            });
            _token = _token.substr( R.$1.length );
          }
          // pseudo
          if (_regExp.pseudo.test( _token )) 
          {
            _token = _token.substr( R.$1.length );
            s  = R.$4; 
            pn = R.$2;
            if (/^nth/.test( pn )) 
            {  
              // normalize nth
              s = _nth[s] || (!/\D/.test( s ) && '0n+'+s) || s; 
            }
            _t.pseudo.push({
              name  : pn,
              value : s
            });
          }
        }
        _tokenCache[_wt] = _t;
      }
      _tokens.push( _tokenCache[_wt] );
    }
    return _tokens;
  },

  // if you are wondering why I don't tokenize and build at the same time
  // then the answer is that originally there was an option to compile
  // xpath query from the tokens, which I've dropped - but still have 
  // the option to reintroduce.
  _compileToken = function ( t, not ) 
  {
    var _cmd = [], 
        _class = 0,
        tn = t.tagName,
        ef = 'elms=filter.',
        ft = {
          '>' : 'byChild',
          '+' : 'byNextSibling',
          '~' : 'bySibling',
          ''  : 'byAncestor'
        };
    not = not || 0;
    if (t.id && !t.operator && !not) 
    {
      _cmd.push( 'elms=filter.idShortCut("'+t.id+'","'+tn+'",elms);' );
    }
    else 
    {
      if (t.operator) 
      {
        _cmd.push( ef + ft[t.operator] + '("' + tn + '",elms);');
      }
      else if (not && tn !== '*') 
      {
        _cmd.push( ef + 'byTagName("' + tn + '",elms,'+not+');');
      }
      else if (!not)
      {
        if (t.className.length && _nativeClass && !not) {
          _cmd.push( ef + 'byClassNameNative("'+t.className.join(' ')+'",elms);' );
          _class = 1;
          if (tn !== '*') {
            _cmd.push( ef + 'byTagName("' + tn + '",elms,'+not+');');
          }
        }
        else {
          _cmd.push( ef + ft[''] + '("' + tn + '",elms);');
        }
      }
      if (t.id) 
      { 
        _cmd.push( ef + 'byId("'+t.id+'",elms,'+not+');' ); 
      }
    }
    if (!_class) { // don't do this if native filter has been used
      
      for (var j=0,m=t.className.length; j<m; j++) 
      {
        _cmd.push( ef + 'byClassName("'+t.className[j]+'",elms,'+not+');' );
      }

    }
    
    for (var j=0,m=t.pseudo.length; j<m; j++) 
    {
      var ps = t.pseudo[j],
          pn = ps.name.replace( /\-/g, '' );
          
      if (pn === 'not' && !not) 
      {
        _cmd.push( _compileToken( _tokenize( ps.value )[0], 1 ) );
      }
      else if (_regExp.nthTest.test( ps.name )) 
      {
        var d = (R.$1 === '-last')   ? 1 : 0;
        var y = (R.$2 === 'of-type') ? tn : '';
        _cmd.push( ef + 'nth("'+ps.value+'",elms,'+not+',"'+y+'",'+d+');' );
      }
      else if (filter[pn]) 
      {
        _cmd.push( ef + pn + '("'+ps.value+'",elms,'+not+');' );
      }
    }
    
    for (var j=0,m=t.attr.length; j<m; j++) 
    {
      var at = t.attr[j],
          op = (filter[at.operator]) ? at.operator : 'attr';
      _cmd.push( 'elms=filter["'+op+'"]("' + at.value + '",elms,'+not+',"'+at.name+'");' );
    }
    
    return _cmd.join('');
  },

  _filterRunner = function (selector, context)
  {

    context = [context || doc];  // frame context
    
    var s, j, t, c = 0,
        _tokens,
        _commands,
        _elements = [],
        _sections = trim( selector ).split(/ *, */); // split by comma

    for (var i=0,l=_sections.length; i<l; i++) 
    {
      if ((s = _sections[i]) && !_selectorCache[s] ) 
      {
        _tokens   = _tokenize( s );
        _commands = []; 
        for (j = 0; t = _tokens[j++]; _commands[c++] = _compileToken( t, 0 ));
        _selectorCache[s] = new Function( 'elms', 'filter', _commands.join( '' ) + 'return elms;' );
      }
      _elements = _elements.concat( _selectorCache[s]( context, filter ) );
    }
    // clean up children cache 
    _wipeNthCache();  
    
    // return collection of unique nodes
    return filter.unique( _elements );
  };
  
  // To save a few bytes I've "compressed" identical loop functions into 
  // this repulsive thing here. Essentially, we are trading load-up speed 
  // for file size.
  var tests = {
    contains   : '(e.innerText||e.textContent||"").indexOf(s)!==-1',
    checked    : 'e.checked',
    disabled   : 'e.disabled',
    empty      : '!e.firstChild',
    onlychild  : '!this.next(e)&&!this.prev(e)',
    lastchild  : '!this.next(e)',                                // this === filter
    firstchild : '!this.prev(e)',                                
    root       : 'e===e.ownerDocument.documentElement',
    byTagName  : 's===e.nodeName',
    '='        : '@a===s',
    '!='       : '@a!==s',
    '^='       : '@a&&a.substr(0,s.length)===s',
    '$='       : '@a&&a.substr(a.length-s.length)===s',
    '*='       : '@a&&a.indexOf(s)!==-1',
    '%='       : '@(a%s)==0',
    '|='       : '@a&&(a==s||a.substr(0,s.length+1)===s+"-")',
    '~='       : '@a&&(" "+a+" ").indexOf(" "+s+" ")!==-1',
    attr       : '!!e.getAttribute(n)'
  };
  var sx, s = '', tst, pre;
  for (var t in tests) {
    tst = tests[t];
    pre = '';
    if (tst.charAt( 0 ) == '@') {
      pre = 'a = e.getAttribute(n);';
      tst = tst.substr( 1 );
    }
    sx = 'var f=[],e,a,i=0,m=0;while(e=elms[i++]){'+ pre + 'if(('+ tst + ')^not){f[m++]=e;}}return f;';
    filter[t] = Function( 's', 'elms', 'not', 'n', sx );
  }
  // Building all function declarations and eval-ing them here could 
  // theoretically give us better performance as declaring functions
  // is faster than creating them this way. But I am trying to avoid 
  // eval and have not really measured any performance gain to merit
  // that approach.
  
  // graceful failure for things not supported
  var fail = 'link,visited,active,hover,focus,target,lang'.split( ',' );
  for (var i=0; i<fail.length; i++) {
    filter[fail[i]] = Function( 's', 'elms', 'not', 'n', 'return [];' );
  }

  // replace filter functions with IE optimized ones if this is IE
  if (msie) {
    for (var method in filterIE) {
      filter[method] = filterIE[method];
    }
  }

  // main function. 
  domget = function ( selector, context )
  {
    // context is document by default 
    context = context || doc;
    
    // graceful failure for selectors that are unsupported
    if (_regExp.unsupported.test( selector )) { return []; }
    
    // use native where available
    if (!_disableNative && 
        context.querySelectorAll && 
        !_regExp.useNative.test( selector ) &&     // There are some things that native cannot do
        !(msie && _regExp.css3.test( selector )))  // IE8 can only do CSS2.1
    {
      // Says the spec:
      //   "The querySelectorAll() methods on the ElementSelector [...] are descendants 
      //    of the element on which the method was invoked and matches the group of 
      //    selectors (selectors), if any."
      var elms, oID = context.id;
      if (context !== doc) {
        context.id = 'domgetContextId'+_dupeKey;
        selector   = selector.replace( /(^|,)\s*/g, '$1#'+context.id+' ' );
      }
      elms = context.querySelectorAll( selector );
      context.id = oID;
      return toArray( elms );  // function always returns array
    }
    
    // shortcut : single id, or tag+id getter
    if (context === doc && selector.indexOf( '#' ) !== -1 && _regExp.tagWithId.test( selector )) 
    {
      var elm = doc.getElementById( R.$2 );
      return (elm && (!R.$1 || elm.nodeName.toUpperCase() === R.$1.toUpperCase())) ? [elm] : [];
    }
    // shortcut : single tag getter
    if (_regExp.tagOnly.test( selector )) 
    {
      return toArray( context.getElementsByTagName( selector ) );
    }
    // shortcut : single class getter where we have native class selector 
    //            (or something like the prototype xpath replacement...)
    if (doc.getElementsByClassName && /^\.(\w+)$/.test( selector )) 
    {
      return toArray( context.getElementsByClassName( R.$1 ) );
    }
    // shortcut : twin tag getter speedup for IE 
    if (msie && selector.indexOf(' ') !== -1 && /^([a-zA-Z]+|\*) ([a-zA-Z]+|\*)$/.test( selector )) 
    {
      var found = [],
          pass1 = context.getElementsByTagName( R.$1 );
      for (var i=0,l=pass1.length; i<l; i++) 
      {
        var pass2 = pass1[i].getElementsByTagName( R.$2 );
        for (var j=0,ll=pass2.length; j<ll; j++) 
        {
          found[found.length] = pass2[j];
        }
      }
      return filter.unique( found );
    }
    return _filterRunner( selector, context );

  };

  // expose the method to where we want it
  window.domget = domget;
  
}());